
<!DOCTYPE html>
<html lang="zh-Hans" class="loading">
<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>jenkins 持续集成 docker服务到堡垒机 - Luis Blog</title>
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="google" content="notranslate" />
    <meta name="keywords" content="Luis,"> 
    <meta name="description" content="java开发工程师，喜欢代码，喜欢技术,简介公司原来的项目发布很繁琐也很普通，最近捣鼓一下jenkins+docker，做一下一键发布，由于公司服务器都加了堡垒机，所以需要解决不能远程ssh部署，整体的思路如下：

jenkins使用pi,"> 
    <meta name="author" content="winter chen"> 
    <link rel="alternative" href="atom.xml" title="Luis Blog" type="application/atom+xml"> 
    <link rel="icon" href="/img/favicon.png"> 
    
    
<link rel="stylesheet" href="/css/diaspora.css">

	<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
    <script>
         (adsbygoogle = window.adsbygoogle || []).push({
              google_ad_client: "ca-pub-8691406134231910",
              enable_page_level_ads: true
         });
    </script>
    <script async custom-element="amp-auto-ads"
        src="https://cdn.ampproject.org/v0/amp-auto-ads-0.1.js">
    </script>
<meta name="generator" content="Hexo 4.2.0"></head>

<body class="loading">
    <span id="config-title" style="display:none">Luis Blog</span>
    <div id="loader"></div>
    <div id="single">
    <div id="top" style="display: block;">
    <div class="bar" style="width: 0;"></div>
    <a class="iconfont icon-home image-icon" href="javascript:;" data-url="https://blog.winterchen.com"></a>
    <div title="播放/暂停" class="iconfont icon-play"></div>
    <h3 class="subtitle">jenkins 持续集成 docker服务到堡垒机</h3>
    <div class="social">
        <div>
            <div class="share">
                <a title="获取二维码" class="iconfont icon-scan" href="javascript:;"></a>
            </div>
            <div id="qr"></div>
        </div>
    </div>
    <div class="scrollbar"></div>
</div>

    <div class="section">
        <div class="article">
    <div class='main'>
        <h1 class="title">jenkins 持续集成 docker服务到堡垒机</h1>
        <div class="stuff">
            <span>四月 14, 2020</span>
            
  <ul class="post-tags-list" itemprop="keywords"><li class="post-tags-list-item"><a class="post-tags-list-link" href="/tags/docker/" rel="tag">docker</a></li><li class="post-tags-list-item"><a class="post-tags-list-link" href="/tags/jenkins/" rel="tag">jenkins</a></li></ul>


        </div>
        <div class="content markdown">
            <h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>公司原来的项目发布很繁琐也很普通，最近捣鼓一下jenkins+docker，做一下一键发布，由于公司服务器都加了堡垒机，所以需要解决不能远程ssh部署，整体的思路如下：</p>
<ol>
<li>jenkins使用pipeline脚本编写（更灵活，方便多套环境复制使用）；</li>
<li>拉取代码并编译成jar包；</li>
<li>将jar包编译为docker镜像；</li>
<li>将镜像上传到本地私有仓库（速度快）</li>
<li>调用写好的跑脚本的服务接口实现在堡垒机中实现docker镜像的新版本发布；</li>
</ol>
<p>关于jenkins的安装方式一开始尝试了很多种方案：</p>
<ul>
<li>jenkins部署在docker容器内，使用远程docker rest api进行镜像打包上传，但是遇到很大的问题就是阿里云私有镜像仓库登录方式不一样，导致登录失败，而且不能使用脚本操作docker，因为jenkins容器内没有docker环境，如果安装docker in docker，这样就太麻烦了，在容器外面就有一套docker环境；(如果不依赖阿里云私有仓库，这种方案就没有关系了)</li>
<li>jenkins安装在有docker环境的服务器内，那么可以使用shell脚本灵活的进行编译上传等操作（适用于比较灵活的使用场景）</li>
</ul>
<h2 id="开始："><a href="#开始：" class="headerlink" title="开始："></a>开始：</h2><h3 id="依赖环境："><a href="#依赖环境：" class="headerlink" title="依赖环境："></a>依赖环境：</h3><ul>
<li>jenkins</li>
<li>docker</li>
</ul>
<h3 id="jenkins安装"><a href="#jenkins安装" class="headerlink" title="jenkins安装"></a>jenkins安装</h3><p>安装步骤请查询相关文档，这里就略过</p>
<h3 id="jenkins安装插件提速"><a href="#jenkins安装插件提速" class="headerlink" title="jenkins安装插件提速"></a>jenkins安装插件提速</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">cd &#123;你的Jenkins工作目录&#125;&#x2F;updates  #进入更新配置位置</span><br><span class="line"></span><br><span class="line">vim default.json</span><br><span class="line"></span><br><span class="line">##替换软件源</span><br><span class="line">:1,$s&#x2F;http:\&#x2F;\&#x2F;updates.jenkins-ci.org\&#x2F;download&#x2F;https:\&#x2F;\&#x2F;mirrors.tuna.tsinghua.edu.cn\&#x2F;jenkins&#x2F;g</span><br></pre></td></tr></table></figure>

<h3 id="安装jenkins插件-HTTP-Request"><a href="#安装jenkins插件-HTTP-Request" class="headerlink" title="安装jenkins插件 HTTP Request"></a>安装jenkins插件 HTTP Request</h3><p>这个插件用于jenkins将docker镜像push到目标仓库之后调用堡垒机中发布服务进行docker镜像的发布</p>
<h3 id="编写jenkins发布脚本"><a href="#编写jenkins发布脚本" class="headerlink" title="编写jenkins发布脚本"></a>编写jenkins发布脚本</h3><p>步骤：新建item -&gt; 选择pipeline（流水线） -&gt; 编辑流水线脚本</p>
<p>注意：</p>
<ul>
<li>在输入框的左下角有：流水线语法，可以根据某些你需要用到的插件生成模板脚本，非常方便</li>
<li>脚本有一点需要注意，单引号内只能为文本不能使用变量，如果需要使用变量，使用双引号；</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br></pre></td><td class="code"><pre><span class="line">pipeline &#123;</span><br><span class="line">   agent any</span><br><span class="line"></span><br><span class="line">   tools &#123;</span><br><span class="line">      &#x2F;&#x2F; Install the Maven version configured as &quot;M3&quot; and add it to the path.</span><br><span class="line">      maven &quot;maven3.6.3&quot;</span><br><span class="line">   &#125;</span><br><span class="line">   </span><br><span class="line">   &#x2F;&#x2F;环境变量，一下变量名称都可以自定义，在后面的脚本中使用</span><br><span class="line">   environment &#123;</span><br><span class="line">      &#x2F;&#x2F;git仓库</span><br><span class="line">	  GIT_REGISTRY &#x3D; &#39;https:&#x2F;&#x2F;github.com&#x2F;WinterChenS&#x2F;my-site.git&#39;</span><br><span class="line">	  &#x2F;&#x2F;分支</span><br><span class="line">	  GIT_BRANCH &#x3D; &#39;sit&#39;</span><br><span class="line">	  &#x2F;&#x2F;profile</span><br><span class="line">	  PROFILES &#x3D; &#39;sit&#39;</span><br><span class="line">	  &#x2F;&#x2F;如果仓库是私有的需要在凭证中添加凭证，然后把id写到这里</span><br><span class="line">	  GITLAB_ACCESS_TOKEN_ID &#x3D; &#39;85465d36-4c3a-469f-b92f-f53dae47fd0c&#39;</span><br><span class="line">	  &#x2F;&#x2F;服务名称</span><br><span class="line">	  SERVICE_NAME &#x3D; &#39;my-site&#39;</span><br><span class="line">	  &#x2F;&#x2F;镜像名称,aaa_sit是命名空间，可以区分不同的环境</span><br><span class="line">	  IMAGE_NAME &#x3D; &quot;127.0.0.1:8999&#x2F;aaa_sit&#x2F;$&#123;SERVICE_NAME&#125;&quot;</span><br><span class="line">	  &#x2F;&#x2F;镜像tag</span><br><span class="line">	  TAG &#x3D; &quot;latest&quot;</span><br><span class="line">	  &#x2F;&#x2F;远程发布服务的地址</span><br><span class="line">	  REMOTE_EXECUTE_HOST &#x3D; &#39;http:&#x2F;&#x2F;10.85.54.33:7017&#x2F;shell&#39;</span><br><span class="line">	  &#x2F;&#x2F;服务开放的端口</span><br><span class="line">	  SERVER_PORT &#x3D; &#39;19070&#39;</span><br><span class="line">	  &#x2F;&#x2F;日志目录，容器内目录</span><br><span class="line">	  LOG_DIR &#x3D; &#39;&#x2F;var&#x2F;logs&#39;</span><br><span class="line">	  &#x2F;&#x2F;宿主机目录</span><br><span class="line">      MAIN_VOLUME &#x3D; &quot;$&#123;LOG_DIR&#125;&#x2F;jar_$&#123;env.SERVER_PORT&#125;&quot;</span><br><span class="line">      &#x2F;&#x2F;jvm参数</span><br><span class="line">      JVM_ARG &#x3D; &quot;-server -Xms512m -Xmx512m  -XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath&#x3D;$&#123;LOG_DIR&#125;&#x2F;dump&#x2F;dump-yyy.log  -XX:ErrorFile&#x3D;$&#123;LOG_DIR&#125;&#x2F;jvm&#x2F;jvm-crash.log&quot;</span><br><span class="line">   &#125;</span><br><span class="line">   </span><br><span class="line">   </span><br><span class="line"></span><br><span class="line">   stages &#123;</span><br><span class="line">      stage(&#39;Build&#39;) &#123;</span><br><span class="line">         steps &#123;</span><br><span class="line">            &#x2F;&#x2F; 获取代码</span><br><span class="line">            git credentialsId: &quot;$&#123;env.GITLAB_ACCESS_TOKEN_ID&#125;&quot;, url: &quot;$&#123;env.GIT_REGISTRY&#125;&quot;, branch: &quot;$&#123;env.GIT_BRANCH&#125;&quot;</span><br><span class="line"></span><br><span class="line">            &#x2F;&#x2F; maven 打包</span><br><span class="line">            sh &quot;mvn -Dmaven.test.failure.ignore&#x3D;true clean package -P $&#123;env.PROFILES&#125;&quot;</span><br><span class="line"></span><br><span class="line">         &#125;</span><br><span class="line"></span><br><span class="line">      &#125;</span><br><span class="line">      </span><br><span class="line">      stage(&#39;Execute shell&#39;) &#123;</span><br><span class="line">	    &#x2F;&#x2F; 将jar包拷贝到Dockerfile所在目录</span><br><span class="line">		steps &#123;</span><br><span class="line">		    &#x2F;&#x2F;注意，这里的目录一定要跟项目实际的目录结构要对应上</span><br><span class="line">			sh &quot;cp $&#123;env.WORKSPACE&#125;&#x2F;$&#123;env.SERVICE_NAME&#125;&#x2F;target&#x2F;*.jar $&#123;env.WORKSPACE&#125;&#x2F;$&#123;env.SERVICE_NAME&#125;&#x2F;src&#x2F;main&#x2F;docker&#x2F;$&#123;env.SERVICE_NAME&#125;.jar&quot;</span><br><span class="line">		</span><br><span class="line">		&#125;</span><br><span class="line">	  &#125;</span><br><span class="line">	  </span><br><span class="line">	  </span><br><span class="line">	 </span><br><span class="line">	  </span><br><span class="line">	  stage(&#39;Image Build And Push&#39;) &#123;</span><br><span class="line"></span><br><span class="line">		steps &#123;</span><br><span class="line">            &#x2F;&#x2F;运行这些脚本的条件就是jenkins运行的服务器有docker环境</span><br><span class="line">            &#x2F;&#x2F;如果jdk版本是你自己编译成的docker镜像，那么首次编译的时候需要pull</span><br><span class="line">			sh &quot;echo &#39;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;开始拉取基础镜像jdk1.8&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#39;&quot;	</span><br><span class="line">			&#x2F;&#x2F;这里根据你的私有仓库而定，如果是使用公共镜像的openjdk那么可以略过这一步</span><br><span class="line">			sh &quot;docker pull 127.0.0.1:8999&#x2F;jdk&#x2F;jdk1.8:8u171&quot;</span><br><span class="line">			sh &quot;echo &#39;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;基础镜像拉取完毕&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#39;&quot;</span><br><span class="line">			</span><br><span class="line">			sh &quot;echo &#39;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;开始编译并上传镜像&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#39;&quot;</span><br><span class="line">			&#x2F;&#x2F;注意目录结构</span><br><span class="line">			sh &quot;cd $&#123;env.WORKSPACE&#125;&#x2F;$&#123;env.SERVICE_NAME&#125;&#x2F;src&#x2F;main&#x2F;docker&#x2F; &amp;&amp; docker build -t $&#123;env.IMAGE_NAME&#125;:$&#123;env.TAG&#125; . &amp;&amp; docker push $&#123;env.IMAGE_NAME&#125;:$&#123;env.TAG&#125;&quot;</span><br><span class="line">			sh &quot;echo &#39;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;镜像上传成功&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#39;&quot;</span><br><span class="line">			</span><br><span class="line">			sh &quot;echo &#39;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;删除本地镜像&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#39;&quot;</span><br><span class="line">			&#x2F;&#x2F;删除本地镜像防止占用资源</span><br><span class="line">			sh &quot;docker rmi $&#123;env.IMAGE_NAME&#125;:$&#123;env.TAG&#125;&quot;</span><br><span class="line">			</span><br><span class="line">		&#125;</span><br><span class="line">		</span><br><span class="line"></span><br><span class="line">	  &#125;</span><br><span class="line">	  </span><br><span class="line">	  stage(&#39;Execute service&#39;) &#123;</span><br><span class="line"></span><br><span class="line">	    &#x2F;&#x2F;请求堡垒机内的发布服务，具体代码后面会给出</span><br><span class="line">		steps &#123;</span><br><span class="line">		    &#x2F;&#x2F;以下整个脚本都依赖jenkins插件：HTTP Request</span><br><span class="line">		    &#x2F;&#x2F;将body转换为json</span><br><span class="line">            script &#123;</span><br><span class="line">              def toJson &#x3D; &#123;</span><br><span class="line">                input -&gt;</span><br><span class="line">                groovy.json.JsonOutput.toJson(input)</span><br><span class="line">            &#125;</span><br><span class="line">			&#x2F;&#x2F;body定义,根据实际情况而定</span><br><span class="line">			def body &#x3D; [</span><br><span class="line">                imageName: &quot;$&#123;env.IMAGE_NAME&#125;&quot;,</span><br><span class="line">                tag:&quot;$&#123;env.TAG&#125;&quot;,</span><br><span class="line">                port:&quot;$&#123;env.SERVER_PORT&#125;&quot;,</span><br><span class="line">                simpleImageName: &quot;$&#123;env.SERVICE_NAME&#125;&quot;,</span><br><span class="line">                envs: [</span><br><span class="line">                    JVM_ARGS: &quot;$&#123;env.JVM_ARG&#125;&quot;</span><br><span class="line">                ],</span><br><span class="line">                volumes: [&quot;$&#123;env.MAIN_VOLUME&#125;:$&#123;env.LOG_DIR&#125;&quot;]</span><br><span class="line">            ]</span><br><span class="line">			</span><br><span class="line">			sh &quot;echo &#39;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;开始调用目标服务器发布&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#39;&quot;</span><br><span class="line">			response &#x3D; httpRequest acceptType: &#39;APPLICATION_JSON&#39;, consoleLogResponseBody: true, contentType: &#39;APPLICATION_JSON&#39;, httpMode: &#39;POST&#39;, requestBody: toJson(body), responseHandle: &#39;NONE&#39;, url: &quot;$&#123;env.REMOTE_EXECUTE_HOST&#125;&quot;</span><br><span class="line">		    sh &quot;echo &#39;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;结束调用目标服务器发布&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#39;&quot;			</span><br><span class="line">		&#125;</span><br><span class="line">		</span><br><span class="line"></span><br><span class="line">	  &#125;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="远程堡垒机发布服务"><a href="#远程堡垒机发布服务" class="headerlink" title="远程堡垒机发布服务"></a>远程堡垒机发布服务</h3><p>远程发布服务其实是一个很简单的执行脚本的服务</p>
<p>ShellRequestDTO.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.winterchen.jenkinsauto.dto;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.validation.constraints.NotBlank;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ShellRequestDTO</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@NotBlank</span></span><br><span class="line">    <span class="keyword">private</span> String imageName;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@NotBlank</span></span><br><span class="line">    <span class="keyword">private</span> String tag;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@NotBlank</span></span><br><span class="line">    <span class="keyword">private</span> String simpleImageName;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@NotBlank</span></span><br><span class="line">    <span class="keyword">private</span> String port;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 环境变量列表</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, String&gt; envs;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; volumes;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getImageName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> imageName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setImageName</span><span class="params">(String imageName)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.imageName = imageName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getTag</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> tag;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setTag</span><span class="params">(String tag)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.tag = tag;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getPort</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> port;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPort</span><span class="params">(String port)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.port = port;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getSimpleImageName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> simpleImageName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setSimpleImageName</span><span class="params">(String simpleImageName)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.simpleImageName = simpleImageName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Map&lt;String, String&gt; <span class="title">getEnvs</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> envs;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setEnvs</span><span class="params">(Map&lt;String, String&gt; envs)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.envs = envs;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> List&lt;String&gt; <span class="title">getVolumes</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> volumes;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setVolumes</span><span class="params">(List&lt;String&gt; volumes)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.volumes = volumes;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> StringBuilder sb = <span class="keyword">new</span> StringBuilder(<span class="string">"ShellRequestDTO&#123;"</span>);</span><br><span class="line">        sb.append(<span class="string">"imageName='"</span>).append(imageName).append(<span class="string">'\''</span>);</span><br><span class="line">        sb.append(<span class="string">", tag='"</span>).append(tag).append(<span class="string">'\''</span>);</span><br><span class="line">        sb.append(<span class="string">", simpleImageName='"</span>).append(simpleImageName).append(<span class="string">'\''</span>);</span><br><span class="line">        sb.append(<span class="string">", port='"</span>).append(port).append(<span class="string">'\''</span>);</span><br><span class="line">        sb.append(<span class="string">", envs="</span>).append(envs);</span><br><span class="line">        sb.append(<span class="string">", volumes="</span>).append(volumes);</span><br><span class="line">        sb.append(<span class="string">'&#125;'</span>);</span><br><span class="line">        <span class="keyword">return</span> sb.toString();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>APIResponse.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.winterchen.jenkinsauto.dto;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">APIRespose</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Integer code;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> T data;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String message;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Boolean success;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> APIRespose <span class="title">success</span><span class="params">()</span></span>&#123;</span><br><span class="line">        APIRespose apiRespose = <span class="keyword">new</span> APIRespose();</span><br><span class="line">        apiRespose.setCode(<span class="number">200</span>);</span><br><span class="line">        apiRespose.setSuccess(<span class="keyword">true</span>);</span><br><span class="line">        <span class="keyword">return</span> apiRespose;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> APIRespose <span class="title">success</span><span class="params">(Object data)</span> </span>&#123;</span><br><span class="line">        APIRespose apiRespose = <span class="keyword">new</span> APIRespose();</span><br><span class="line">        apiRespose.setCode(<span class="number">200</span>);</span><br><span class="line">        apiRespose.setSuccess(<span class="keyword">true</span>);</span><br><span class="line">        apiRespose.setData(data);</span><br><span class="line">        <span class="keyword">return</span> apiRespose;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> APIRespose <span class="title">fail</span><span class="params">(String message)</span> </span>&#123;</span><br><span class="line">        APIRespose apiRespose = <span class="keyword">new</span> APIRespose();</span><br><span class="line">        apiRespose.setCode(<span class="number">500</span>);</span><br><span class="line">        apiRespose.setSuccess(<span class="keyword">false</span>);</span><br><span class="line">        apiRespose.setMessage(message);</span><br><span class="line">        <span class="keyword">return</span> apiRespose;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">   <span class="comment">//get,set省略</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>BaseController.java</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.winterchen.jenkinsauto.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.winterchen.jenkinsauto.dto.APIRespose;</span><br><span class="line"><span class="keyword">import</span> com.winterchen.jenkinsauto.dto.ShellRequestDTO;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.Logger;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.LoggerFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.validation.annotation.Validated;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.PostMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestBody;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.BufferedReader;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStreamReader;</span><br><span class="line"><span class="keyword">import</span> java.text.MessageFormat;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping</span>(<span class="string">"/shell"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BaseController</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Logger LOGGER = LoggerFactory.getLogger(BaseController.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostMapping</span>(<span class="string">""</span>)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> APIRespose <span class="title">executeShell</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">        @RequestBody</span></span></span><br><span class="line"><span class="function"><span class="params">        @Validated</span></span></span><br><span class="line"><span class="function"><span class="params">        ShellRequestDTO requestDTO</span></span></span><br><span class="line"><span class="function"><span class="params">    )</span> </span>&#123;</span><br><span class="line">        LOGGER.info(<span class="string">"当前请求参数："</span> + requestDTO.toString());</span><br><span class="line">        StringBuilder sb = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            doExecuteShell(requestDTO, sb);</span><br><span class="line">            <span class="keyword">return</span> APIRespose.success(sb.toString());</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="keyword">return</span> APIRespose.fail(e.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">doExecuteShell</span><span class="params">(ShellRequestDTO requestDTO, StringBuilder sb)</span> <span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">        <span class="comment">//停止旧的容器</span></span><br><span class="line">        stopContainer(requestDTO.getSimpleImageName(), sb);</span><br><span class="line">        <span class="comment">//stopContainerByImageId(requestDTO.getImageName(), sb);</span></span><br><span class="line">        <span class="comment">//删除旧的容器</span></span><br><span class="line">        removeContainer(requestDTO.getSimpleImageName(), sb);</span><br><span class="line">        <span class="comment">//removeContainerByImageId(requestDTO.getImageName(),sb);</span></span><br><span class="line">        <span class="comment">//删除旧的镜像</span></span><br><span class="line">        removeImage(requestDTO.getImageName(), sb);</span><br><span class="line">        removeNoneImages(sb);</span><br><span class="line">        <span class="comment">//拉取最新的镜像</span></span><br><span class="line">        pullImage(requestDTO.getImageName(), requestDTO.getTag(), sb);</span><br><span class="line">        <span class="comment">//运行最新镜像</span></span><br><span class="line">        runImage(requestDTO, sb);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">pullImage</span><span class="params">(String imageName, String tag, StringBuilder sb)</span> <span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">        execute(MessageFormat.format(<span class="string">"docker pull &#123;0&#125;:&#123;1&#125;"</span>, imageName, tag), sb);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">stopContainer</span><span class="params">(String simpleImageName, StringBuilder sb)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            execute(<span class="string">"docker stop "</span> + simpleImageName, sb);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            LOGGER.error(<span class="string">"停止容器失败"</span>, e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">removeImage</span><span class="params">(String imageName, StringBuilder sb)</span>  </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            execute(<span class="string">"docker rmi -f "</span> + imageName, sb);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            LOGGER.error(<span class="string">"删除镜像失败"</span>, e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">removeNoneImages</span><span class="params">(StringBuilder sb)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            execute(<span class="string">"docker ps -a | grep `docker images -f 'dangling=true' -q` | awk '&#123;print $1&#125;'"</span>, sb);</span><br><span class="line">            execute(<span class="string">"docker stop $(docker ps -a | grep `docker images -f 'dangling=true' -q` | awk '&#123;print $1&#125;')"</span>, sb);</span><br><span class="line">            execute(<span class="string">"docker ps -a | grep `docker images -f 'dangling=true' -q` | awk '&#123;print $1&#125;'"</span>,sb);</span><br><span class="line">            execute(<span class="string">"docker rm  $(docker ps -a | grep `docker images -f 'dangling=true' -q` | awk '&#123;print $1&#125;')"</span>, sb);</span><br><span class="line">            execute(<span class="string">"docker images -f 'dangling=true'|awk '&#123;print $3&#125;'"</span>, sb);</span><br><span class="line">            execute(<span class="string">"docker image rm -f  `docker images -f 'dangling=true'|awk '&#123;print $3&#125;'`"</span>, sb);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            LOGGER.error(<span class="string">"删除none镜像失败"</span>, e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">removeContainer</span><span class="params">(String simpleImageName, StringBuilder sb)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            execute(<span class="string">"docker rm "</span> + simpleImageName, sb);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            LOGGER.error(<span class="string">"删除容器失败"</span>, e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">runImage</span><span class="params">(ShellRequestDTO requestDTO, StringBuilder sb)</span> <span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">        StringBuilder shell = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">        shell.append(<span class="string">"docker run -p "</span>).append(requestDTO.getPort()).append(<span class="string">":"</span>).append(requestDTO.getPort());</span><br><span class="line">        shell.append(<span class="string">" --network=host "</span>);</span><br><span class="line">        shell.append(<span class="string">" --name="</span>).append(requestDTO.getSimpleImageName());</span><br><span class="line">        shell.append(<span class="string">" -d "</span>);</span><br><span class="line">        formatEnv(requestDTO.getEnvs(), shell);</span><br><span class="line">        formatVolumes(requestDTO.getVolumes(), shell);</span><br><span class="line">        shell.append(requestDTO.getImageName()).append(<span class="string">":"</span>).append(requestDTO.getTag());</span><br><span class="line">        execute(shell.toString(), sb);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">formatVolumes</span><span class="params">(List&lt;String&gt; volumes, StringBuilder shell)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (volumes == <span class="keyword">null</span> || <span class="number">0</span> == volumes.size()) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        volumes.forEach(volume -&gt; &#123;</span><br><span class="line">            shell.append(<span class="string">" -v "</span>);</span><br><span class="line">            shell.append(<span class="string">" '"</span>).append(volume).append(<span class="string">"' "</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">formatEnv</span><span class="params">(Map&lt;String, String&gt; env, StringBuilder shell)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (env == <span class="keyword">null</span> || env.isEmpty()) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (Map.Entry&lt;String, String&gt; entry : env.entrySet()) &#123;</span><br><span class="line">            shell.append(<span class="string">" -e "</span>);</span><br><span class="line">            shell.append(entry.getKey()).append(<span class="string">"='"</span>).append(entry.getValue()).append(<span class="string">"' "</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">execute</span><span class="params">(String command, StringBuilder sb)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        BufferedReader infoInput = <span class="keyword">null</span>;</span><br><span class="line">        BufferedReader errorInput = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            LOGGER.info(<span class="string">"======================当前执行命令======================"</span>);</span><br><span class="line">            LOGGER.info(command);</span><br><span class="line">            LOGGER.info(<span class="string">"======================当前执行命令======================"</span>);</span><br><span class="line">            <span class="comment">//执行脚本并等待脚本执行完成</span></span><br><span class="line">            String[] commands = &#123; <span class="string">"/bin/sh"</span>, <span class="string">"-c"</span>, command &#125;;</span><br><span class="line">            Process process = Runtime.getRuntime().exec(commands);</span><br><span class="line">            <span class="comment">//写出脚本执行中的过程信息</span></span><br><span class="line">            infoInput = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(process.getInputStream()));</span><br><span class="line">            errorInput = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(process.getErrorStream()));</span><br><span class="line">            String line = <span class="string">""</span>;</span><br><span class="line">            <span class="keyword">while</span> ((line = infoInput.readLine()) != <span class="keyword">null</span>) &#123;</span><br><span class="line">                sb.append(line).append(System.lineSeparator());</span><br><span class="line">                LOGGER.info(line);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">while</span> ((line = errorInput.readLine()) != <span class="keyword">null</span>) &#123;</span><br><span class="line">                sb.append(line).append(System.lineSeparator());</span><br><span class="line">                LOGGER.error(line);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//阻塞执行线程直至脚本执行完成后返回</span></span><br><span class="line">            process.waitFor();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (infoInput != <span class="keyword">null</span>) &#123;</span><br><span class="line">                    infoInput.close();</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (errorInput != <span class="keyword">null</span>) &#123;</span><br><span class="line">                    errorInput.close();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h2 id="相关资源"><a href="#相关资源" class="headerlink" title="相关资源"></a>相关资源</h2><ul>
<li><a href="https://docs.docker.com/engine/api/v1.24/" target="_blank" rel="noopener">docker rest api 官方文档</a></li>
<li><a href="https://jenkins.io/zh/doc/" target="_blank" rel="noopener">jenkins 官方文档</a></li>
<li><a href="https://docs.docker.com/engine/" target="_blank" rel="noopener">docker 官方文档</a></li>
</ul>

            <!--[if lt IE 9]><script>document.createElement('audio');</script><![endif]-->
            <audio id="audio" loop="1" preload="auto" controls="controls" data-autoplay="false">
                <source type="audio/mpeg" src="">
            </audio>
            
                <ul id="audio-list" style="display:none">
                    
                        
                            <li title='0' data-url='https://raw.githubusercontent.com/WinterChenS/imgrpo/master/mp3/%E6%96%B0%E8%A3%A4%E5%AD%90-%E7%94%9F%E6%B4%BB%E5%9B%A0%E4%BD%A0%E8%80%8C%E7%81%AB%E7%83%AD.mp3'></li>
                        
                    
                </ul>
            
        </div>
        
    <div id='gitalk-container' class="comment link"
		data-enable='false'
        data-ae='false'
        data-ci='77f2adc33e0112d086d7'
        data-cs='e926aa3a621556609b2c2b76d89320fa524e23cd'
        data-r='WinterChenS.github.io'
        data-o='WinterChenS'
        data-a='WinterChenS'
        data-d='false'
    >查看评论</div>


    </div>
    
</div>


    </div>
</div>
</body>


<script src="//lib.baomitu.com/jquery/1.8.3/jquery.min.js"></script>
<script src="/js/plugin.js"></script>
<script src="/js/typed.js"></script>
<script src="/js/diaspora.js"></script>


<link rel="stylesheet" href="/photoswipe/photoswipe.css">
<link rel="stylesheet" href="/photoswipe/default-skin/default-skin.css">


<script src="/photoswipe/photoswipe.min.js"></script>
<script src="/photoswipe/photoswipe-ui-default.min.js"></script>


<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>
    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">
        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>
        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">
            <div class="pswp__top-bar">
                <!--  Controls are self-explanatory. Order can be changed. -->
                <div class="pswp__counter"></div>
                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
                <button class="pswp__button pswp__button--share" title="Share"></button>
                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                      <div class="pswp__preloader__cut">
                        <div class="pswp__preloader__donut"></div>
                      </div>
                    </div>
                </div>
            </div>
            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div> 
            </div>
            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>
            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>
            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>
        </div>
    </div>
</div>





<!-- Google Analytics -->
<script type="text/javascript">
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'G-30C04D6TMS', 'auto');
  ga('send', 'pageview');
</script>
<!-- End Google Analytics -->


</html>
